/**
 * 
 */
package classificationEtSelection;

import general.*;

import io.ExporterPagesToHTML;

import java.util.Vector;

import criteres.Criteres;

/**
 * Classe générale permettant de lancer l"algo de classificationEtSelection 
 * <br><br>
 * Algo de classificationEtSelection
 * 
 *initialisation : 1 cluster, toutes les pages dedans <br>
 *tant que les centres des clusters bougent<br>
 * pour tous les clusters<br>
 *  parcourir les pages du cluster<br>
 *   attribuer la page au cluster le plus proche si assez proche (seuil)<br>
 *   si pas assez proche : creer un nouveau cluster<br>
 *   recalculer le centre des clusters modifie<br>
 *  stocker les anciens centres<br>
 *  recalculer les centres des clusters<br>

 * @author remi
 *@version 1.0
 */
public class ClassificationEtSelection {

	/**
	 * Represente l'ensemble des cluster pour les pages
	 */
	public static Vector<Cluster> clusters = new Vector<Cluster>();

	//toto
	
		/**
	 * Fonction permettant de lancer la copie du resultat de la classif et selection
	 * @param clusters les clusters sur lesquel on va faire la selection
	 * @return true ou false si erreur
	 */
	public static boolean lancerLaCopie(Vector<Cluster> clusters){
		
		//nettoyage du repertoire de sortie ( ie suppression puis creation)
		//suppression du repertoire s'il existe
		if(VariablesGlobales.fichierSortieClassification.exists()==true){
			VariablesGlobales.fichierSortieClassification.delete();
		}
		VariablesGlobales.fichierSortieClassification.mkdir();

		
		//remplissage du contenu
		int compteurDebug = 0;
		for(Cluster cluster : clusters){
			compteurDebug++;
			ExporterPagesToHTML.clusterToFichier(cluster, VariablesGlobales.fichierSortieClassification);
			System.err.println(compteurDebug);
		}
		return false;
		
		
	}




	/**
	 * Lancer la classification (creation de clusters de pages similaires)
	 * @param pages les pages qui serront repartie selon les clusters
	 */
	public void lancerLaClassification(Vector<Page> pages){
		//mise en forme des donnees (normalisation)
		Criteres.normalisation(pages);
		
		//importation des pages situées dans le repertoire choisi par l'utilisateur ou par defaut:
			
		//initialisation:
		clusters = new Vector <Cluster>();
		//insertion de toutes les pages dans le cluster 0
		clusters.add(new Cluster(pages,0));
		// calcul du centre du cluster
		majCentres();
		// initialisation du nombre de clusters		
		int nombreDeClusters = 1;
		
		boolean lesClustersNeBougentPlus = false;
		int numero;
		int i;
		boolean pasLoin;
		
		while (!(lesClustersNeBougentPlus)) //les clusters bougent
		{
			//on vide les clusters
			this.videsClusters();
			
			//parcours de toutes les pages et attribution a un cluster
			i = 0; 
			
			pasLoin = true;
			
			while ((i < pages.size()) && (pasLoin)) // tant qu'on ne rencontre pas de point trop eloigne de tous les cluster et que 
			{ 
				numero = attribuerPageCluster(pages.get(i)); //on regarde le cluster le plus proche	
				if (numero == -1) // Le point n'a pas de cluster proche
				{
					// on cree un nouveau cluster
					clusters.add(new Cluster(pages.get(i),nombreDeClusters));
					nombreDeClusters++;
					//on quitte la boucle while
					pasLoin = false;
				}
				else // la page appartient au cluster "numero"
				{
					clusters.get(numero).ajouterPage(pages.get(i));// on ajoute la page au cluster
				}
				i++;
			}
			
			majCentres(); //mise a jour des centres des clusters
					
			if (pasLoin == false) // un cluster a ete cree
			{
				lesClustersNeBougentPlus = false;
			}
			else
			{
				lesClustersNeBougentPlus = true;
			}
			
			int j = 0;
			while ((lesClustersNeBougentPlus) && (j < ClassificationEtSelection.clusters.size()))
			{
				if (Point.distance(clusters.get(j).getCentreAncien(),clusters.get(j).getCentre()) > ParametresClassifications.seuilMouvementCentre)
				{
					lesClustersNeBougentPlus = false;
				}
				j++;
			}
		}
		
		// remplissage des champs "utile" et "numeroCluster" pour chaque page 
		Cluster aux;
		boolean utile;
		for(i = 0; i < clusters.size(); i++)
		{
			aux = clusters.get(i);
			aux.majStat();
			aux.calculUtile();
			utile = aux.isUtile();
			for(int j = 0; j < clusters.get(i).getPages().size(); j++)
			{
				aux.getPages().get(j).setNumeroCluster(i);
				aux.getPages().get(j).setUtile(utile);
			}
		}
		
	}
	
	/**
	 * met à jour les centres des clusters
	 */
	public void majCentres(){
		int i = 0;
		while (i < ClassificationEtSelection.clusters.size()){
			
			if (ClassificationEtSelection.clusters.get(i).getPages().size() != 0) // on met a jour si le cluster n'est pas vide
			{
				ClassificationEtSelection.clusters.get(i).majCentre();
				i++;
			}
			else
			{
				ClassificationEtSelection.clusters.remove(i);
			}
			
		}
		return;
	}

	/**
	 * Vide les clusters
	 */
	public void videsClusters(){
		for(int i = 0; i < clusters.size(); i++ )
		{
			clusters.get(i).viderPagesCluster();
		}
		return;
	}
	
	/**
	 * Attribue une page au cluster le plus proche. Si la distance est plus grande que le seuil de classification renvoie -1 sinon le numero du cluster
	 */
	public int attribuerPageCluster(Page page){
		double min = 10000000;
		int numeroDuCluster = -1;
		for(int i = 0; i < ClassificationEtSelection.clusters.size(); i ++){
			if (Point.distance(clusters.get(i).getCentre(),page.getPoint()) < min)
			{
				min = Point.distance(clusters.get(i).getCentre(),page.getPoint());
				numeroDuCluster = i;
			}
		}
		if (min > ParametresClassifications.seuilClassification){
			numeroDuCluster = -1;
		}
		
		return numeroDuCluster;
	}
	
	/**
	 * constructeur classique
	 */
	public ClassificationEtSelection() {
		// TODO Auto-generated constructor stub
	}
	
	
	/**
	 * constructeur qui utilise ou non la distance speciale
	 * @param utiliserDistancePonderee
	 */
	public ClassificationEtSelection(boolean utiliserDistancePonderee) {
		// TODO ClassificationEtSelection constructeur avec arguments
	}
	
	/**
	 * main de test de la classe
	 * @param args pas d'argument prévu
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

	/**
	 * @return les differents clusters 
	 */
	public static Vector<Cluster> getClusters() {
		return clusters;
	}

	public static void setClusters(Vector<Cluster> clusters) {
		ClassificationEtSelection.clusters = clusters;
	}
	
	/**
	 * affiche les centres des clusters dans la sortie err [debug]
	 */
	private void afficheClusters(){
		for(int i = 0; i < clusters.size(); i++)
		{
			System.err.println("centre du cluster");
			System.err.println(i);
			System.err.println(clusters.get(i).getCentre().getPoint());
		}
	}

}
